package com.cnswhy.cloud.server.core.wallet.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.cnswhy.cloud.common.core.exception.BizException;
import com.cnswhy.cloud.common.core.mybatis.conditions.Wraps;
import com.cnswhy.cloud.common.core.utils.SystemClockUtil;
import com.cnswhy.cloud.common.redis.annotation.RedisLock;
import com.cnswhy.cloud.common.redis.model.LockTimeoutStrategy;
import com.cnswhy.cloud.common.redis.service.IdGeneratorService;
import com.cnswhy.cloud.server.common.entity.enumeration.TransType;
import com.cnswhy.cloud.server.common.entity.enumeration.WalletType;
import com.cnswhy.cloud.server.core.entity.CustomerWallet;
import com.cnswhy.cloud.server.core.entity.SysConfig;
import com.cnswhy.cloud.server.core.entity.WalletTransDtl;
import com.cnswhy.cloud.server.core.query.QueryGenerator;
import com.cnswhy.cloud.server.core.service.CustomerWalletService;
import com.cnswhy.cloud.server.core.service.SysConfigService;
import com.cnswhy.cloud.server.core.service.WalletTransDtlService;
import com.cnswhy.cloud.server.core.wallet.WalletDtlService;
import com.cnswhy.cloud.server.core.wallet.WalletService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
@Slf4j
public class WalletServiceImpl implements WalletService {
    @Autowired
    CustomerWalletService customerWalletService;
    @Autowired
    WalletDtlService walletDtlService;
    @Autowired
    SysConfigService sysConfigService;
    @Autowired
    WalletTransDtlService walletTransDtlService;

    @Override
    public CustomerWallet getCustomerWalletById(Long walletId) {
        CustomerWallet customerWallet = customerWalletService.getById(walletId);
        if(customerWallet == null){
            throw new BizException("账户不存在");
        }
        return customerWallet;
    }

    public CustomerWallet getCustomerWallet(Long customerId, WalletType walletType){
        CustomerWallet customerWallet = customerWalletService.getOne(Wraps.<CustomerWallet>lbQ().eq(CustomerWallet::getCustomerId,customerId).eq(CustomerWallet::getWalletType,walletType));
        if(customerWallet == null){
            throw new BizException("账户不存在");
        }
        return customerWallet;
    }

    @Override
    @RedisLock(name = "CustomerWallet", waitTime = 10,leaseTime = 60,keys = {"#customerId","#walletType"},lockTimeoutStrategy = LockTimeoutStrategy.FAIL_FAST)
    public CustomerWallet checkAndCreate(Long customerId, WalletType walletType, Long initBalance) {
        try {
            CustomerWallet customerWallet = getCustomerWallet(customerId,walletType);
            return customerWallet;
        }catch (BizException e){
        }
        CustomerWallet customerWallet = new CustomerWallet();
        customerWallet.setCustomerId(customerId);
        customerWallet.setWalletType(walletType);
        customerWallet.setAvlbBalance(initBalance);
        customerWalletService.save(customerWallet);
        log.info("新增钱包:{} {}",customerId,walletType.getDesc());
        return customerWallet;
    }

    @Override
    @RedisLock(name = "CustomerWallet", waitTime = 10,leaseTime = 60,keys = {"#customerId","#walletType"},lockTimeoutStrategy = LockTimeoutStrategy.FAIL_FAST)
    public CustomerWallet create(Long customerId, WalletType walletType, Long initBalance) {
        try {
            CustomerWallet customerWallet = getCustomerWallet(customerId,walletType);
            return customerWallet;
        }catch (BizException e){
        }
        CustomerWallet customerWallet = new CustomerWallet();
        customerWallet.setCustomerId(customerId);
        customerWallet.setWalletType(walletType);
        customerWallet.setAvlbBalance(initBalance);
        customerWalletService.save(customerWallet);
        return customerWallet;
    }

    @Override
    @RedisLock(name = "CustomerWallet", waitTime = 10,leaseTime = 60,keys = {"#customerId","#walletType"},lockTimeoutStrategy = LockTimeoutStrategy.FAIL_FAST)
    public CustomerWallet add(Long customerId, WalletType walletType, TransType transType, Long transAmt,String orderId) {
        //CustomerWallet customerWallet = getCustomerWallet(customerId,walletType);
        CustomerWallet customerWallet = checkAndCreate(customerId,walletType,0L);
        WalletTransDtl walletTransDtl = walletDtlService.addWalletTransDtl(customerWallet.getId(),customerWallet.getCustomerId(),transType,orderId,customerWallet.getAvlbBalance(),transAmt);

        customerWallet.setAvlbBalance(walletTransDtl.getEndBal());
        customerWalletService.updateById(customerWallet);
        return customerWallet;
    }

    @Override
    public CustomerWallet add(Long customerId, WalletType walletType, TransType transType, Long transAmt, String orderId, String spellOrderId, String splitFrom,int splitLevel) {
        CustomerWallet customerWallet = checkAndCreate(customerId,walletType,0L);
        WalletTransDtl walletTransDtl = walletDtlService.addWalletTransDtl(customerWallet.getId(),customerWallet.getCustomerId(),transType,orderId,customerWallet.getAvlbBalance(),transAmt,spellOrderId,splitFrom,splitLevel);

        customerWallet.setAvlbBalance(walletTransDtl.getEndBal());
        customerWalletService.updateById(customerWallet);
        return customerWallet;
    }

    @Override
    @RedisLock(name = "CustomerWallet", waitTime = 10,leaseTime = 60,keys = {"#customerId","#walletType"},lockTimeoutStrategy = LockTimeoutStrategy.FAIL_FAST)
    public boolean checkDed(Long customerId, WalletType walletType, Long transAmt) {
        CustomerWallet customerWallet = getCustomerWallet(customerId,walletType);
        if(customerWallet.getAvlbBalance().compareTo(transAmt) < 0){
            return false;
        }
        return true;
    }

    @Override
    @RedisLock(name = "CustomerWallet", waitTime = 10,leaseTime = 60,keys = {"#customerId","#walletType"},lockTimeoutStrategy = LockTimeoutStrategy.FAIL_FAST)
    public CustomerWallet ded(Long customerId, WalletType walletType,  TransType transType, Long transAmt,String orderId) {
        CustomerWallet customerWallet = getCustomerWallet(customerId,walletType);
        WalletTransDtl walletTransDtl = walletDtlService.addWalletTransDtl(customerWallet.getId(),customerWallet.getCustomerId(),transType,orderId,customerWallet.getAvlbBalance(),-transAmt);

        customerWallet.setAvlbBalance(walletTransDtl.getEndBal());
        customerWalletService.updateById(customerWallet);
        return customerWallet;
    }

    @Override
    @RedisLock(name = "CustomerWallet", waitTime = 10,leaseTime = 60,keys = {"#customerId","#walletType"},lockTimeoutStrategy = LockTimeoutStrategy.FAIL_FAST)
    public CustomerWallet fronzen(Long customerId, WalletType walletType, TransType transType, Long transAmt,String orderId) {
        CustomerWallet customerWallet = getCustomerWallet(customerId,walletType);
        customerWallet.setAvlbBalance(customerWallet.getAvlbBalance() - transAmt);
        customerWallet.setFronzenBalance(customerWallet.getFronzenBalance() + transAmt);
        customerWalletService.updateById(customerWallet);
        return customerWallet;
    }

    @Override
    @RedisLock(name = "CustomerWallet", waitTime = 10,leaseTime = 60,keys = {"#customerId","#walletType"},lockTimeoutStrategy = LockTimeoutStrategy.FAIL_FAST)
    public CustomerWallet unfronzen(Long customerId, WalletType walletType, TransType transType, Long transAmt,String orderId) {
        CustomerWallet customerWallet = getCustomerWallet(customerId,walletType);
        customerWallet.setAvlbBalance(customerWallet.getAvlbBalance() + transAmt);
        customerWallet.setFronzenBalance(customerWallet.getFronzenBalance() - transAmt);
        customerWalletService.updateById(customerWallet);
        return customerWallet;
    }

    @Override
    @RedisLock(name = "CustomerWallet", waitTime = 10,leaseTime = 60,keys = {"#customerId","#walletType"},lockTimeoutStrategy = LockTimeoutStrategy.FAIL_FAST)
    public CustomerWallet unfronzenAndDed(Long customerId, WalletType walletType, TransType transType, Long transAmt,String orderId) {
        CustomerWallet customerWallet = getCustomerWallet(customerId,walletType);
        customerWallet.setAvlbBalance(customerWallet.getAvlbBalance() + transAmt);
        customerWallet.setFronzenBalance(customerWallet.getFronzenBalance() - transAmt);
        WalletTransDtl walletTransDtl = walletDtlService.addWalletTransDtl(customerWallet.getId(),customerWallet.getCustomerId(),transType,orderId,customerWallet.getAvlbBalance(),-transAmt);

        customerWallet.setAvlbBalance(walletTransDtl.getEndBal());
        customerWalletService.updateById(customerWallet);
        return customerWallet;
    }
    @Autowired
    IdGeneratorService idGeneratorService;
    @Override
    @RedisLock(name = "transfer", waitTime = 10,leaseTime = 60,keys = {"#customerId","#walletType"},lockTimeoutStrategy = LockTimeoutStrategy.FAIL_FAST)
    public void transfer(Long customerId, WalletType walletType, TransType transType, Long transAmt) {
        CustomerWallet customerWallet = checkAndCreate(customerId, walletType, 0L);
        if (!checkDed(customerWallet.getCustomerId(), walletType, transAmt)) {
            throw new BizException(walletType.getDesc() + "：余额不足");

        }
        //checkTransferTimes(walletType,transType,customerId,customerWallet.getId());
        String orderId = transType.getCode() + idGeneratorService.genCommonIdString();
        ded(customerWallet.getCustomerId(), walletType, transType, transAmt, orderId);
        add(customerWallet.getCustomerId(), WalletType.BALANCE, transType, transAmt, orderId);
    }

    private void checkTransferTimes(WalletType walletType, TransType transType,Long customerId,Long customerWalletId){
        try {
            String sysConfigKey = null;
            /*if(WalletType.LOVE_BALANCE.eq(walletType)){
                sysConfigKey = "love_wallet_count";
            } else if(WalletType.CONTRIBUTION_VALUE.eq(walletType)){
                sysConfigKey = "contribution_wallet_count";
            }else if(WalletType.SPELL_BALANCE.eq(walletType)){
                sysConfigKey = "spell_wallet_count";
            }else if(WalletType.SHARE_BALANCE.eq(walletType)){
                sysConfigKey = "share_wallet_count";
            }else if(WalletType.COUPON.eq(walletType)){
                sysConfigKey = "coupon_wallet_count";
            }else if(WalletType.TEAM_BALANCE.eq(walletType)){
                sysConfigKey = "team_wallet_count";
            }else if(WalletType.SPLIT_BALANCE.eq(walletType)){
                sysConfigKey = "split_wallet_count";
            }else if(WalletType.SMALL_BALANCE.eq(walletType)){
                sysConfigKey = "split_wallet_count";
            }else{
                return;
            }*/
            WalletTransDtl walletTransDtl = new WalletTransDtl();
            walletTransDtl.setCustomerId(customerId);
            walletTransDtl.setCustomerWalletId(customerWalletId);
            walletTransDtl.setSettDate(SystemClockUtil.getSettDateyyyyMMdd());
            walletTransDtl.setTransType(transType);
            QueryWrapper<WalletTransDtl> queryWrapper = QueryGenerator.initQueryWrapper(walletTransDtl);
            List<WalletTransDtl> list = walletTransDtlService.list(queryWrapper);

            SysConfig sysConfigCount = sysConfigService.getOne(Wraps.<SysConfig>lbQ().eq(SysConfig::getConfigKey, sysConfigKey));
            int count = Integer.parseInt(sysConfigCount.getConfigValue());
            if (count <= list.size()){
                throw new BizException("当日转出次数达到上限");
            }
        } catch (NumberFormatException e) {
            e.printStackTrace();
        }
    }
}
